#requires -version 2.0 
function Get-NaCluster{
	<#
	.Synopsis
		Get useful information about the status of the clustering service.
	.Description
		Get useful information about the status of the clustering service. If the monitor is not
		initialized, this returns an error.
	.Parameter Server
	    NaServer to query
	.Example
		PS > Get-NaCluster -Server (New-NaServer)
	.Outputs
   		PSObject
   	.Link
   		Enable-NaCluster
   		Disable-NaCluster
   		Start-NaClusterGiveback
   		Start-NaClusterTakeOver
   	#>
	[CmdletBinding(SupportsShouldProcess=$FALSE,SupportsTransactions=$False,ConfirmImpact="low",DefaultParameterSetName="")]
	param ( 
		[Parameter(Position=0,ValueFromPipeline=$True,HelpMessage="NaServer to query")]
		[NetApp.SDK.NaServer] 
		$server = (Get-NaServer)
	)
    process{
	    Try{
	        $result = ([xml]$server.Invoke("cf-status")).results
        }
        catch [NetApp.Manage.NaApiFailedException] {
            Write-Warning $_.Exception.GetBaseException().message
            return $null
        }      
        write-output "" | Select-Object @{
	 		Name = 'Server'
			Expression = {$Server.Server}
        }, 
        @{
			Name = "Partner"
			Expression = {$result."Partner"}
		},
        @{
			Name = "State"
			Expression = {$result."state"}
		},
        @{
			Name = "Time"
			Expression = {(ConvertFrom-NaTime $result."current-time")}
		},
        @{
			Name = "Enabled"
			Expression = {(ConvertFrom-Nabool $result."is-enabled")}
		},
        @{		
            Name = "InterconnectUp"
			Expression = {(ConvertFrom-Nabool $result."is-interconnect-up")}
		},
        @{
			Name = "TakeoverFailureReason"
			Expression = {$result."takeover-failure-reason"}
		},
        @{
			Name = "TimeMaster"
			Expression = {$result."time-master-status"}
		},
        @{
			Name = "TimeUntilTakeover"
			Expression = {$result."time-until-takeover"}
		}
	}
}
function Enable-NaCluster {
	<#
	.Synopsis
		Enables the takeover capability of this filer in the cluster.
	.Description
		Enables the takeover capability of this filer in the cluster.
 		This spawns a process to enable the service
	.Parameter Server
	    NaServer to query
	.Example
		PS > Enable-NaCluster
	.Outputs
   		PSObject
   	.Link
   		Get-NaCluster
   		Disable-NaCluster
   		Start-NaClusterGiveback
   		Start-NaClusterTakeOver
   	#>
	[CmdletBinding(SupportsShouldProcess=$true,SupportsTransactions=$False,ConfirmImpact="low",DefaultParameterSetName="")]
	param ( 
		[Parameter(Position=0,ValueFromPipeline=$True,HelpMessage="NaServer to query")]
		[NetApp.SDK.NaServer] 
		$server = (Get-NaServer)
	)
	process {
	    if ($pscmdlet.ShouldProcess($server.Server, "Enabling cluster service")) {
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
			if ($?){
				return Get-NaCluster -Server $server
			}
	    }
	}
}
function Disable-NaCluster {
	<#
	.Synopsis
		Disables the takeover capability of this filer in the cluster.
	.Description
		Enables the takeover capability of this filer in the cluster.
 		This spawns a process to Disable the service
	.Parameter Server
	    NaServer to query
	.Example
		PS > Disable-NaCluster
	.Outputs
   		PSObject
   	.Link
   		Get-NaCluster
   		Enable-NaCluster
   		Start-NaClusterGiveback
   		Start-NaClusterTakeOver
   	#>
	[CmdletBinding(SupportsShouldProcess=$true,SupportsTransactions=$False,ConfirmImpact="low",DefaultParameterSetName="")]
	param ( 
		[Parameter(Position=0,ValueFromPipeline=$True,HelpMessage="NaServer to query")]
		[NetApp.SDK.NaServer] 
		$server = (Get-NaServer)
	)
	process{
		if ($pscmdlet.ShouldProcess($Sserver.Server,"disabling cluster service")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
			if ($?) {
				Get-NaCluster -Server $server
			}
	    }
	}
}
function Start-NaClusterTakeover {
	<#
	.Synopsis
		Initiates a takeover of the partner.
	.Description
		Initiates a takeover of the partner. If Automatic giveback is enabled. 
 		Control will be returned to partner once it boots up.
	.Parameter Force
		This causes takeover to be immediately initiated. The taken over node, if up, does not get
		to shut things down in an orderly manner so the takeover of the resources takes longer. 
		This is the type of takeover that is done during normal cluster operation when one of the
		nodes goes away (dies).
	.Parameter Server
	    NaServer to query
	.Example
		Start-NaClusterTakeover
	.Outputs
   		PSObject
   	.Link
   		Get-NaCluster
   		Enable-NaCluster
   		Disable-NaCluster
   		Start-NaClusterGiveback
   	#>
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="High",DefaultParameterSetName="")]
	param ( 
		[Parameter(Position=0,ValueFromPipeline=$True,HelpMessage="NaServer to query")]
		[NetApp.SDK.NaServer] 
		$server = (Get-NaServer),
		
		[Parameter()]
		[Switch]
		$Force
	)
	Begin {
		Function CheckPartner {
			Param([NetApp.SDK.NaServer]$Svr)
			$F = Get-NaCluster -Server $Svr
			switch ($F) {
				{(-Not $F.Enabled)} {return $false}
				{(-Not $F.State -eq 'CONNECTED') -and -not $force} {return $false}
				Default{
					$script:Partner = $F.Partner
					Return $True	
				}
			}
		}
	}
	process{
		if (CheckPartner -Svr $server){
			$request = New-Object Netapp.Manage.NaElement -ArgumentList @("cf-takeover")
			if ($force){ 
				$request.AddNewChild("force",$TRUE)
			}
			if ($pscmdlet.ShouldProcess($Server.Server, "Initiating a Takeover of partner $script:Partner")){
				try {
					$server.InvokeElem($request)|out-null
				}
				catch [NetApp.Manage.NaApiFailedException]{
					Write-Warning $_.Exception.GetBaseException().message
					continue;
				}
				if ($?){
					return Get-NaCluster -Server $server
				}
			}
		}
	}
}

function Start-NaClusterGiveback {
	<#
	.Synopsis
		Initiates a giveback of partner resources.
	.Description
		Initiates a giveback of partner resources. Once the giveback is complete, the automatic 
		takeover capability is disabled until the partner is rebooted. A giveback fails if 
		outstanding CIFS sessions, active system dump processes, or other filer operations makes
 		a giveback dangerous or disruptive.
	.Parameter Force
		This allows a giveback to proceed even if there are outstanding CIFS sessions, active 
 		system dump processes, or other filer operations makes a giveback dangerous or disruptive 
 		as long as it would not result in data corruption or filer error. 
	.Parameter Server
	    NaServer to query
	.Example
		PS > Start-NaClusterGiveback
	.Outputs
   		PSObject
   	.Link
   		Get-NaCluster
   		Enable-NaCluster
   		Disable-NaCluster
   		Start-NaClusterTakeOver
   	#>
	[CmdletBinding(SupportsShouldProcess=$True,SupportsTransactions=$False,ConfirmImpact="high",DefaultParameterSetName="")]	
	param (
		[Parameter()]
		[switch] 
		$force,

		[Parameter(Position=0,ValueFromPipeline=$True,HelpMessage="NaServer to query")]
		[NetApp.SDK.NaServer] 
		$server = (Get-NaServer)
	)
	process{
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("cf-giveback")
		if ($force){ 
			$request.AddNewChild("force",$TRUE)
		}
		if ($pscmdlet.ShouldProcess($server.Server, "Initiating a Giveback to partner node")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
			if ($?){
				return Get-NaCluster -Server $server
			}
		}
	}
}
Function Test-NaClusterNegotiatedFailover {
	<#
	.Synopsis
		Returns the status of the negotiated failover module.
	.Description
		Returns the status of the negotiated failover module. Negotiated failover is a general 
 		facility which supports negotiated failover on the basis of decisions made by various 
 		modules.
	.Parameter Module
		Name of the module to test, true if clusterfailover for this module is enabled
	.Parameter Server
	    NaServer to query
	.Example
		# status of the negotiated failover module 'disk_shelf'
		PS > Test-NaClusterNegotiatedFailover -Module 'disk_shelf'
	.Outputs
   		System.bool
   	.Link
 		Get-NaCluster
 		Enable-NaClusterNegotiatedFailover
 		Disable-NaClusterNegotiatedFailover
    #>
	[CmdletBinding(SupportsShouldProcess=$FALSE,SupportsTransactions=$False,ConfirmImpact="low",DefaultParameterSetName="")]
	param (
		[Parameter(Position=0,mandatory=$true,HelpMessage="module currently supported is 'disk_shelf'")]
		[ValidateSet("disk_shelf")]
		[Alias("Module")]
		[string] 
		$Name,
	
		[Parameter(Position=1,ValueFromPipeline=$True,HelpMessage="NaServer to query")]
		[NetApp.SDK.NaServer] 
		$server = (Get-NaServer)
	)
	process {
			$request = New-Object Netapp.Manage.NaElement -ArgumentList @("cf-negotiated-failover-status")
			$request.AddNewChild("module",$Name)
			Write-output (ConvertFrom-NaBool $server.InvokeElem($request).getchildcontent("is-enabled"))
	}
}
Function Enable-NaClusterNegotiatedFailover {
	<#
	.Synopsis
		Enables negotiated failover. 
	.Description
		Enables negotiated failover. disk_shelf is the negotiated failover module currently supported
	.Parameter Name
		Name of the Module to enable negotiated failover on.  Currently only 'Disk_Shelf' is supported.
	.Parameter Server
	    NaServer to query
	.Example
		Enable negotiated failover on module 'disk_shelf'
 		PS > Enable-NaClusterNegotiatedFailover -Name 'disk_shelf'
 	.Link
 		Get-NaCluster
 		Test-NaClusterNegotiatedFailover
 		Disable-NaClusterNegotiatedFailover
   #>
	[CmdletBinding(SupportsShouldProcess=$true,SupportsTransactions=$False,ConfirmImpact="low",DefaultParameterSetName="")]
	param (
		[Parameter(Position=0,mandatory=$true,ValueFromPipelineByPropertyName=$true,HelpMessage="module currently supported is 'disk_shelf'")]
		[ValidateSet("disk_shelf")]
		[Alias("Module")]
		[string] 
		$Name,

		[Parameter(Position=1,ValueFromPipeline=$True,HelpMessage="NaServer to query")]
		[NetApp.SDK.NaServer] 
		$server = (Get-NaServer)
	)
	process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("cf-negotiated-failover-enable")
		$request.AddNewChild("module",$Name)
		if ($pscmdlet.ShouldProcess($server.Server, "Enabling negotiated failover on $Name")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
		}
	}
}
function Disable-NaClusterNegotiatedFailover {
	<#
	.Synopsis
		Disables negotiated failover. 
	.Description
		Disables negotiated failover. disk_shelf is the negotiated failover module currently supported
	.Parameter Name
		Name of the Module to Disables negotiated failover on.  Currently only 'Disk_Shelf' is supported.
	.Parameter Server
	    NaServer to query
	.Example
		Enable negotiated failover on module 'disk_shelf'
 		PS > Disable-NaClusterNegotiatedFailover -Name 'disk_shelf'
 	.Link
 		Get-NaCluster
 		Test-NaClusterNegotiatedFailover
 		Enable-NaClusterNegotiatedFailover
   	#>
	[CmdletBinding(SupportsShouldProcess=$true,SupportsTransactions=$False,ConfirmImpact="low",DefaultParameterSetName="")]
	param (
		[Parameter(Position=0,mandatory=$true,ValueFromPipelineByPropertyName=$true,HelpMessage="module currently supported is 'disk_shelf'")]
		[ValidateSet("disk_shelf")]
		[Alias("Module")]
		[string] 
		$Name,

		[Parameter(Position=1,ValueFromPipeline=$True,HelpMessage="NaServer to query")]
		[NetApp.SDK.NaServer] 
		$server = (Get-NaServer)
	)
	process {
		$request = New-Object Netapp.Manage.NaElement -ArgumentList @("cf-negotiated-failover-disable")
		$request.AddNewChild("module",$Name)
		if ($pscmdlet.ShouldProcess($Server.Server, "Disabling negotiated failover on $Name")){
			try {
				$server.InvokeElem($request)|out-null
			}
			catch [NetApp.Manage.NaApiFailedException]{
				Write-Warning $_.Exception.GetBaseException().message
				continue;
			}
		}
	}
}

